
import redis
import json
import logging
from django.conf import settings
from .exceptions import RedisOperationException
import time

logger = logging.getLogger(__name__)

class RedisClient:
    _instance = None
    RECONNECT_INTERVAL = 5  # 重连间隔(秒)
    MAX_RETRIES = 3  # 最大重试次数

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
            cls._reconnect()
        return cls._instance

    @classmethod
    def _reconnect(cls):
        retry_count = 0
        while retry_count < cls.MAX_RETRIES:
            try:
                cls._instance.client = redis.Redis(
                    host=settings.REDIS_HOST,
                    port=settings.REDIS_PORT,
                    db=settings.REDIS_DB,
                    password=settings.REDIS_PASSWORD,
                    decode_responses=True,
                    socket_timeout=5,
                    socket_connect_timeout=3,
                    health_check_interval=30
                )
                cls._instance.client.ping()
                return
            except Exception as e:
                retry_count += 1
                logger.error(f"Redis连接失败(尝试 {retry_count}/{cls.MAX_RETRIES}): {str(e)}")
                if retry_count < cls.MAX_RETRIES:
                    time.sleep(cls.RECONNECT_INTERVAL)
        raise RedisOperationException("无法连接到Redis服务器")

    def _ensure_connection(self):
        try:
            self.client.ping()
        except:
            self._reconnect()

    def get(self, key, default=None):
        self._ensure_connection()
        try:
            value = self.client.get(key)
            return json.loads(value) if value else default
        except Exception as e:
            logger.warning(f"Redis读取失败: {str(e)}")
            return default

    def setex(self, key, timeout, value):
        self._ensure_connection()
        try:
            return self.client.setex(
                key,
                timeout,
                json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
            )
        except Exception as e:
            logger.error(f"Redis写入失败: {str(e)}")
            raise RedisOperationException()

    def delete(self, *keys):
        self._ensure_connection()
        try:
            return self.client.delete(*keys)
        except Exception as e:
            logger.error(f"Redis删除失败: {str(e)}")
            raise RedisOperationException()

    def cache_product(self, product, timeout=1800):
        """缓存商品信息标准格式"""
        self._ensure_connection()
        cache_data = {
            'id': product.id,
            'name': product.name,
            'price': float(product.price),
            'stock': product.stock,
            'status': product.status,
            'updated_at': product.updated_at.timestamp(),
            'main_image': product.main_image
        }
        try:
            self.setex(f"product:{product.id}", timeout, cache_data)
            return True
        except RedisOperationException:
            return False

    def get_cached_product(self, product_id):
        """获取缓存的商品信息"""
        return self.get(f"product:{product_id}")
